package model;

import java.io.IOException;
import java.util.ArrayList;

import util.FileIOHelper;
import vo.ParkHistory;
import vo.ParkInfo;

import exception.NotAvailException;

/**
 * ParkingAreaManager.java
 * 설명 : 주차정보를 리스트 형태로 관리
 * 		  Singleton 패턴으로 구현
 * @since : 2013. 6. 2.
 * @author : kyeongwookma
 * @version : v1.0
 */
public class ParkingAreaManager implements IParkingArea {

	private static final String FILE_NAME = "parking_info.txt";
	private static final int MAX_PARK = 20;
	private static final int FEE = 800;
	private static ParkingAreaManager parkingArea = new ParkingAreaManager();


	private ArrayList<ParkInfo> parkingList;

	private ParkingAreaManager() { 
		initList();		
	}

	public static ParkingAreaManager getInstance() {

		if(parkingArea == null) {
			return new ParkingAreaManager();
		} else
			return parkingArea;
	}


	/**
	 * 설명 :  parking_info.txt 파일에 주차 정보를 저장
	 * 변경이력 : 
	 * -----------------------------------------------------------------
	 * 변경일       작성자       변경내용  
	 * ------------ ------------ ---------------------------------------
	 * 2013. 6. 2. kyeongwookma          최초 작성 
	 * -----------------------------------------------------------------
	 * @since : 2013. 6. 2.
	 * @author : kyeongwookma
	 * @throws IOException
	 */ 	
	public void saveInfo() throws IOException {
		FileIOHelper ioHelper = new FileIOHelper();
		StringBuilder sb = new StringBuilder();

		for(int i = 0; i < MAX_PARK; ++i) {

			ParkInfo info = parkingList.get(i);

			sb.append(info.getAreaName()  + info.getCarNumber() + info.getPrice());

			ioHelper.writeFile(FILE_NAME, sb.toString());
		}

	}

	public void initList() {
		parkingList = new ArrayList<ParkInfo>();

		// 20 개의 주차 구역을 초기화
		for(int i = 0; i < MAX_PARK; ++i) {

			ParkInfo info = new ParkInfo();
			info.setAreaName("IT-" + (i+1));
			parkingList.add(info);		
		}

	}



	/**
	 * 설명 :  입력받은 inputArea와 parkingList를 비교해 해당 구역에 주차된 차가 있는지 확인
	 * 변경이력 : 
	 * -----------------------------------------------------------------
	 * 변경일       작성자       변경내용  
	 * ------------ ------------ ---------------------------------------
	 * 2013. 6. 5. junmooyeon          최초 작성 
	 * -----------------------------------------------------------------
	 * @since : 2013. 6. 5.
	 * @author : junmooyeon
	 */ 	
	public boolean checkArea(ParkInfo info) 
	{
		String inputArea = info.getAreaName();

		for(int i = 0; i < MAX_PARK; ++i) {

			ParkInfo preinfo = parkingList.get(i);

			if(inputArea.equals(preinfo.getAreaName()))
			{
				if(preinfo.getCarNumber() != null) 
				{
						return false;
				}
			}
		}
		return true;
	}

	/**
	 * 설명 : 주차 정보를 추가한다. synchronized 키워드로 mutex를 보장
	 * 변경이력 : 
	 * -----------------------------------------------------------------
	 * 변경일       작성자       변경내용  
	 * ------------ ------------ ---------------------------------------
	 * 2013. 6. 2. kyeongwookma          최초 작성 
	 * -----------------------------------------------------------------
	 * @since : 2013. 6. 2.
	 * @author : kyeongwookma
	 * @param info
	 */ 	
	@Override
	public synchronized void addParkInfo(ParkInfo info)  {

		// 사용자가 입력한 주차구역 중.
		String inputArea = info.getAreaName();

		for(int i = 0; i < MAX_PARK; ++i) {

			String areaName = parkingList.get(i).getAreaName();	

			// 같은 주차 구역에 주차시킴.
			if(inputArea.equals(areaName)) {

				// 비어있으면 입
				if(checkArea(info)) {
					parkingList.set(i, info);
				} 
				// 그렇지 않으면 예외처
				else
					try {
						throw new NotAvailException();
					} catch (NotAvailException e) {
						e.printStackTrace();
					}
			}
		}

		FileIOHelper fileWriter = new FileIOHelper();
		try {
			fileWriter.writeFile(FILE_NAME, info);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 설명 : 주차구역 정보를 검색하여 삭제
	 * 변경이력 : 
	 * -----------------------------------------------------------------
	 * 변경일       작성자       변경내용  
	 * ------------ ------------ ---------------------------------------
	 * 2013. 6. 2. kyeongwookma 최초 작성
	 * 2013. 6. 4  kyeongwookma history(요금) 추가.
	 * -----------------------------------------------------------------
	 * @since : 2013. 6. 2.
	 * @author : kyeongwookma
	 * @param area
	 */ 	

	// TODO
	@Override
	public void removeParkInfo(String area, String outDate, String outTime) {

		ParkHistory history;

		// 구역 명을 파라메터로 받아 삭제
		for(int i = 0; i < MAX_PARK; ++i) {

			ParkInfo info = parkingList.get(i);			

			// 구역명에서 주차 구역을 찾음
			if(area.equals(info.getAreaName()))
			{
				// 주차구역내 내역 얻음
				ArrayList<ParkHistory> historys = info.getHistory();
				String carNum = info.getCarNumber();

				for(int j = 0; j < historys.size(); ++j) {

					history = historys.get(j);

					// 내역내에서 차번이 존재하는 경우
					if(carNum.equals(history.getCarNum())) {

						// 나가는 시간 설정
						history.setOutDate(outDate);
						history.setOutTime(outTime);

						historys.set(j,history);

						// 주차 구역 해지
						info.setCarNumber(null);
						info.setParked(false);
						info.setHistory(historys);	
					} 
				}
			}

			parkingList.set(i, info);

			FileIOHelper ioHelper = new FileIOHelper();
			try {
				ioHelper.writeFile(FILE_NAME, info);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}


	/**
	 * 설명 : 주차 구역 중 차량번호가 비어있는 주차구역을 추출
	 * 변경이력 : 
	 * -----------------------------------------------------------------
	 * 변경일       작성자       변경내용  
	 * ------------ ------------ ---------------------------------------
	 * 2013. 6. 2. kyeongwookma          최초 작성 
	 * -----------------------------------------------------------------
	 * @since : 2013. 6. 2.
	 * @author : kyeongwookma
	 * @return
	 */ 	
	@Override
	public ArrayList<String> getAvailList() {

		ArrayList<String> vancanList = new ArrayList<String>();

		// 비어있는 인덱스 값을 받아
		// 스트링 리스트에 "IT - index" 형태로 추가 후 리턴.
		for(int i = 0; i < MAX_PARK; ++i) {

			ParkInfo info = parkingList.get(i);

			if(info.getCarNumber() == null) {
				vancanList.add(new String("IT-" + (i+1)));
			}
		}
		return vancanList;
	}

	/**
	 * 설명 : 차 번호로 주차구역을 검색
	 * 변경이력 : 
	 * -----------------------------------------------------------------
	 * 변경일       작성자       변경내용  
	 * ------------ ------------ ---------------------------------------
	 * 2013. 6. 2. kyeongwookma          최초 작성 
	 * -----------------------------------------------------------------
	 * @since : 2013. 6. 2.
	 * @author : kyeongwookma
	 * @param carNum
	 * @return
	 */ 	
	@Override
	public String getCarLocation(String carNum) {

		// 차번호로 주차 구역 검색.
		for(int i = 0; i < MAX_PARK; ++i) {

			ParkInfo info = parkingList.get(i);

			if(carNum.equals(info.getCarNumber())) {
				return info.getAreaName();
			}

		}
		return null;
	}

	@Override
	public int getAreaSize() {
		return parkingList.size();
	}


	@Override
	public ArrayList<ParkInfo> getParkingList() {
		return parkingList;
	}


	@Override
	public int getParkCount() {

		int parkCount = 0;

		for(int i = 0; i < parkingList.size(); ++i) {

			if(parkingList.get(i).isParked())
				++parkCount;
		}

		return parkCount;
	}


	@Override
	public int getAvailCount() {
		return getAreaSize() - getParkCount();
	}

	@Override
	public ArrayList<ParkHistory> getParkHistory(String date, String areaName) {

		ArrayList<ParkHistory> parkHistorys = null;
		ParkHistory history = null;

		for(int i = 0; i < parkingList.size(); ++i) {

			ParkInfo info = parkingList.get(i);

			// 사용자가 검색하기 원하는 구역 중
			if(areaName.equals(info.getAreaName())) {
				parkHistorys = info.getHistory();

				// 주차 내역을 검색
				for(int j = 0; j < parkHistorys.size(); ++j) {
					history = parkHistorys.get(j);

					// 같은 날짜 내
					if(date.equals(history.getInDate())) {

						// 출차한 기록내역이 있으면
						if(history.getOutTime() != null)
						{
							String inTime = history.getInTime();
							String outTime = history.getOutTime();

							// 시간에서 앞 두자리 시가만 추출하여
							inTime = inTime.substring(0, 2);
							outTime = outTime.substring(0, 2);

							// 시간 * 800 으로 요금 추산
							int price = (Integer.parseInt(outTime) - Integer.parseInt(inTime)) * FEE;						

							// 요금 저장 및 주차 내역 저장
							history.setPrice(price);
							parkHistorys.set(j,history);
						}
					}
					else
						return null;
				}
			}	
		}

		return parkHistorys;
	}

	public ParkInfo getParkInfo(String areaName) {

		for(int i = 0; i < parkingList.size(); ++i) {

			if(areaName.equals(parkingList.get(i).getAreaName()))
				return parkingList.get(i);			
		}
		return new ParkInfo();		
	}

}
